package jp.co.coretechno;

import java.awt.Color;
import java.awt.Graphics;
import java.util.Random;

public class Field {
	public static final int PATTERN_WIDTH = 14;
	public static final int PATTERN_HEIGHT = 24;
	public static final int BLOCK_PIXEL = 16;
	
	private Cell[][] pattern;
	private Block block;
	private int blockX;
	private int blockY;
	private int score = 0;
	private int eraseLineCount = 0;
	private boolean isGameOver;
	
	public Field() {
		pattern = new Cell[PATTERN_HEIGHT][PATTERN_WIDTH];
		
		for (int y = 0; y < PATTERN_HEIGHT; y++) {
			for (int x = 0; x < PATTERN_WIDTH; x++) {
				pattern[y][x] = new Cell();
			}
		}
		
		for (int x = 0; x < PATTERN_WIDTH; x++) {
			pattern[PATTERN_HEIGHT - 1][x].setCell(Color.DARK_GRAY);
		}
		
		for (int y = 0; y < PATTERN_HEIGHT; y++) {
			pattern[y][0].setCell(Color.DARK_GRAY);
			pattern[y][PATTERN_WIDTH - 1].setCell(Color.DARK_GRAY);
		}
		
		block = new Block();
		
		blockX = 7;
		blockY = 0;
		
		isGameOver = false;
	}
	
	public void drawField(Graphics g) {
		g.setColor(Color.BLUE);
		for (int y = 0; y < PATTERN_HEIGHT; y++) {
			for (int x = 0; x < PATTERN_WIDTH; x++) {
				pattern[y][x].draw(g, x, y);
			}
		}
		
		block.draw(g, blockX, blockY);
		
		g.setColor(Color.BLUE);
		g.drawString("SCORE " + score, PATTERN_WIDTH * (BLOCK_PIXEL + 1), BLOCK_PIXEL);
		g.drawString("LINE  " + eraseLineCount, PATTERN_WIDTH * (BLOCK_PIXEL + 1), BLOCK_PIXEL * 2);
	}
	
	public boolean createNewBlock() {
		block.setRandomBlock();
		blockX = 7;
		blockY = 0;
		
		for (int y = 0; y < Block.BLOCK_HEIGHT; y++) {
			for (int x = 0; x < Block.BLOCK_WIDTH; x++) {
				if (block.isHit(x, y) && !pattern[y + blockY][x + blockX].isEmpty()) {
					return false;
				}
			}
		}
		
		return true;
	}
		
	public void moveDown() {
		if (isGameOver) {
			return;
		}
		
		if (canMoveBlock(0, 1)) {
			blockY++;
		} else {
			write();
			eraseLine();
			if (!createNewBlock()) {
				isGameOver = true;
				
				for (int y = 0; y < PATTERN_HEIGHT; y++) {
					for (int x = 0; x < PATTERN_WIDTH; x++) {
						pattern[y][x].setCell(Color.DARK_GRAY);
					}
				}
			}
		}
	}
	
	public void moveLeft() {
		if (canMoveBlock(-1, 0)) {
			blockX--;
		}
	}
	
	public void moveRight() {
		if (canMoveBlock(1, 0)) {
			blockX++;
		}
	}
	
	public boolean canMoveBlock(int moveX, int moveY) {
		int bx = blockX + moveX;
		int by = blockY + moveY;
		
		for (int y = 0; y < Block.BLOCK_HEIGHT; y++) {
			for (int x = 0; x < Block.BLOCK_WIDTH; x++) {
				if (this.isHit(bx + x, by + y) && block.isHit(x, y)) {
					return false;
				}
			}
		}
		
		return true;
	}
	
	public boolean isHit(int x, int y) {
		if (x < 0 || x > PATTERN_WIDTH - 1) {
			return true;
		}
		if (y < 0 || y > PATTERN_HEIGHT - 1) {
			return true;
		}
		return !pattern[y][x].isEmpty();
	}
	
	private void write() {
		for (int y = 0; y < Block.BLOCK_HEIGHT; y++) {
			for (int x = 0; x < Block.BLOCK_WIDTH; x++) {
				if (block.isHit(x, y)) {
					if (blockY + y < PATTERN_HEIGHT 
						&& blockX + x < PATTERN_WIDTH)
					{
						pattern[blockY + y][blockX + x].setCell(block.getColor(x, y));
					}
				}
			}
		}
	}
	
	public void rotateBlockLeft() {
		block.rotateLeft();
	}
	
	public boolean canRotateBlockLeft() {
		return block.canRotateLeft(this, blockX, blockY);
	}
	
	public void rorateBlockRight() {
		block.rotateRight();
	}
	
	public boolean canRotateBlockRight() {
		return block.canrotateRight(this, blockX, blockY);
	}
	
	public void eraseLine() {
		int count = 0;
		
		for (int y = 0; y < PATTERN_HEIGHT - 1; y++) {
			boolean isLineFull = true;
			for (int x = 1; x < PATTERN_WIDTH - 1; x++) {
				if (pattern[y][x].isEmpty()) {
					isLineFull = false;
					break;
				}
			}
			
			if (isLineFull) {
				count++;
				for (int dy = y; dy > 0; dy--) {
					for (int dx = 1; dx < PATTERN_WIDTH - 1; dx++) {
						if (!pattern[dy - 1][dx].isEmpty()) {
							pattern[dy][dx].setCell(pattern[dy - 1][dx].getColor());
						} else {
							pattern[dy][dx].resetCell();
						}
					}
				}
				for (int dx = 1; dx < PATTERN_WIDTH - 1; dx++) {
					pattern[0][dx].resetCell();
				}
			}
		}
		
		eraseLineCount += count;
		
		switch (count) {
		case 0:
			break;
		case 1:
			score += 10;
			break;
		case 2:
			score += 20;
			break;
		case 3:
			score += 40;
			break;
		case 4:
			score += 80;
			break;
		case 5:
			score += 120;
			break;
		default:
			score += 120;
			break;
		}
	}
}
